
package com.gitee.jmash.oidc.oauth2.impl;

import org.apache.commons.lang3.StringUtils;
import com.gitee.jmash.oidc.oauth2.enums.GrantType;
import com.gitee.jmash.oidc.oauth2.enums.GrantWay;
import com.gitee.jmash.oidc.oauth2.enums.ScopeType;
import com.gitee.jmash.oidc.oauth2.models.ErrorResponse;
import com.gitee.jmash.oidc.oauth2.models.TokenCodeModel;
import com.gitee.jmash.oidc.oauth2.models.TokenResponse;
import com.gitee.jmash.oidc.oauth2.utils.IdTokenUtil;
import com.gitee.jmash.oidc.web.Constant;
import com.gitee.jmash.oidc.web.OidcMapper;
import com.gitee.jmash.rbac.RbacFactory;
import com.gitee.jmash.rbac.entity.TokenEntity;
import com.xyvcard.ops.OpsFactory;
import com.xyvcard.ops.entity.OpsClientEntity;
import jakarta.enterprise.context.Dependent;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.ws.rs.core.Response;

/**
 * authorization_code 换取 access_token.
 *
 * @author CGD
 *
 */
@Dependent
public class OauthCodeTokenImpl {

  /** authorization_code --> access_token. */
  public Response token(@Valid TokenCodeModel token, HttpServletRequest request) {

    // 1.验证GrantType
    if (!GrantType.authorization_code.equals(token.getGrantType())) {
      return ErrorResponse.createResponse("invalid_grant", "invalid_grant不匹配.");
    }
    // 2.验证clientId、clientSecret
    OpsClientEntity client = OpsFactory.getOpsClientRead(Constant.TENANT)
        .findBySecret(token.getClientId(), token.getClientSecret());
    if (client == null || !client.allowGrantWay(GrantWay.code.name())) {
      return ErrorResponse.createResponse("invalid_client", "client_id身份认证错误或授权方式不一致.");
    }
    // 3.验证Code
    TokenEntity tokenEntity = RbacFactory.getUserRead(Constant.TENANT)
        .findTokenByAuthzCode(token.getClientId(), token.getCode());
    if (null == tokenEntity || tokenEntity.hasCodeExpire()
        || StringUtils.isNotBlank(tokenEntity.getAccessToken())) {
      return ErrorResponse.createResponse("invalid_request", "AuthorizationCode错误.");
    }

    // 4.生成并记录AccessToken
    tokenEntity = RbacFactory.getUserWrite(Constant.TENANT).authzCodeToken(token.getClientId(),
        token.getCode(), tokenEntity.getSubject());

    TokenResponse resp = new TokenResponse();
    OidcMapper.INSTANCE.update(resp, tokenEntity);

    // id_token
    if (StringUtils.contains(resp.getScope(), ScopeType.openid.name())) {
      String idToken = IdTokenUtil.createIdToken(tokenEntity);
      resp.setIdToken(idToken);
    }

    return Response.ok().entity(resp).build();
  }
}
